#include "processtable.h"
#include <iomanip>
#include <sstream>
#include <iostream>
#include <gtkmm/dialog.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/filechooserdialog.h>
#include <glibmm/spawn.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <fstream>

ProcessTable::ProcessTable()
    : m_selected_pid(-1) {
    
    // 创建数据模型
    m_ref_tree_model = Gtk::ListStore::create(m_columns);
    m_tree_view.set_model(m_ref_tree_model);
    
    // 添加列并设置排序ID
    Gtk::TreeView::Column* col_name = Gtk::manage(new Gtk::TreeView::Column("进程名称"));
    // 设置进程名称列宽度和文字截断
    Gtk::CellRendererText* renderer_name = Gtk::manage(new Gtk::CellRendererText());
    col_name->pack_start(*renderer_name);
    col_name->add_attribute(renderer_name->property_text(), m_columns.m_col_name);
    renderer_name->property_ellipsize() = Pango::ELLIPSIZE_END;
    renderer_name->property_width_chars() = 20;
    renderer_name->property_max_width_chars() = 20;
    // 启用tooltip显示完整进程名称
    renderer_name->property_ellipsize_set() = true;
    
    m_tree_view.append_column(*col_name);
    col_name->set_sort_column(m_columns.m_col_name);
    
    // 为进程名称列添加查询提示功能
    m_tree_view.set_has_tooltip(true);
    m_tree_view.signal_query_tooltip().connect([this](int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) -> bool {
        Gtk::TreeModel::Path path;
        if (m_tree_view.get_tooltip_context_path(x, y, keyboard_tooltip, path)) {
            // 获取坐标点所在的列
            int bin_x, bin_y;
            Gtk::TreeViewColumn* column = nullptr;
            m_tree_view.convert_widget_to_bin_window_coords(x, y, bin_x, bin_y);
            
            // 获取该位置的列
            int cell_y, cell_height;
            m_tree_view.get_path_at_pos(bin_x, bin_y, path, column, cell_y, cell_height);
            
            // 检查是否是进程名称列（第一列）
            if (column == m_tree_view.get_column(0)) {
                Gtk::TreeIter iter = m_ref_tree_model->get_iter(path);
                if (iter) {
                    Gtk::TreeModel::Row row = *iter;
                    std::string full_name = row[m_columns.m_col_name];
                    tooltip->set_text(full_name);
                    return true;
                }
            }
        }
        return false;
    });
    
    Gtk::TreeView::Column* col_pid = Gtk::manage(new Gtk::TreeView::Column("PID"));
    col_pid->pack_start(m_columns.m_col_pid);
    m_tree_view.append_column(*col_pid);
    col_pid->set_sort_column(m_columns.m_col_pid);
    
    Gtk::TreeView::Column* col_status = Gtk::manage(new Gtk::TreeView::Column("状态"));
    col_status->pack_start(m_columns.m_col_status);
    m_tree_view.append_column(*col_status);
    col_status->set_sort_column(m_columns.m_col_status);
    
    Gtk::TreeView::Column* col_user = Gtk::manage(new Gtk::TreeView::Column("用户"));
    col_user->pack_start(m_columns.m_col_user);
    m_tree_view.append_column(*col_user);
    col_user->set_sort_column(m_columns.m_col_user);
    
    Gtk::TreeView::Column* col_cpu = Gtk::manage(new Gtk::TreeView::Column("CPU%"));
    col_cpu->pack_start(m_columns.m_col_cpu);
    m_tree_view.append_column(*col_cpu);
    col_cpu->set_sort_column(m_columns.m_col_cpu);
    
    Gtk::TreeView::Column* col_memory = Gtk::manage(new Gtk::TreeView::Column("内存"));
    col_memory->pack_start(m_columns.m_col_memory);
    m_tree_view.append_column(*col_memory);
    col_memory->set_sort_column(m_columns.m_col_memory);
    
    Gtk::TreeView::Column* col_time = Gtk::manage(new Gtk::TreeView::Column("运行时间"));
    col_time->pack_start(m_columns.m_col_time);
    m_tree_view.append_column(*col_time);
    col_time->set_sort_column(m_columns.m_col_time);
    
    Gtk::TreeView::Column* col_command = Gtk::manage(new Gtk::TreeView::Column("命令行"));
    col_command->pack_start(m_columns.m_col_command);
    m_tree_view.append_column(*col_command);
    col_command->set_sort_column(m_columns.m_col_command);
    
    // 设置命令行列宽度和文字截断
    Gtk::CellRendererText* renderer_command = Gtk::manage(new Gtk::CellRendererText());
    col_command->pack_start(*renderer_command);
    col_command->add_attribute(renderer_command->property_text(), m_columns.m_col_command);
    renderer_command->property_ellipsize() = Pango::ELLIPSIZE_END;
    renderer_command->property_width_chars() = 30;
    renderer_command->property_max_width_chars() = 30;
    
    Gtk::TreeView::Column* col_priority = Gtk::manage(new Gtk::TreeView::Column("优先级"));
    col_priority->pack_start(m_columns.m_col_priority);
    m_tree_view.append_column(*col_priority);
    col_priority->set_sort_column(m_columns.m_col_priority);
    
    // 添加磁盘和网络相关列
    Gtk::TreeView::Column* col_disk_read = Gtk::manage(new Gtk::TreeView::Column("磁盘读取"));
    col_disk_read->pack_start(m_columns.m_col_disk_read);
    m_tree_view.append_column(*col_disk_read);
    col_disk_read->set_sort_column(m_columns.m_col_disk_read);
    
    Gtk::TreeView::Column* col_disk_write = Gtk::manage(new Gtk::TreeView::Column("磁盘写入"));
    col_disk_write->pack_start(m_columns.m_col_disk_write);
    m_tree_view.append_column(*col_disk_write);
    col_disk_write->set_sort_column(m_columns.m_col_disk_write);
    
    Gtk::TreeView::Column* col_network_recv = Gtk::manage(new Gtk::TreeView::Column("网络接收"));
    col_network_recv->pack_start(m_columns.m_col_network_recv);
    m_tree_view.append_column(*col_network_recv);
    col_network_recv->set_sort_column(m_columns.m_col_network_recv);
    
    Gtk::TreeView::Column* col_network_send = Gtk::manage(new Gtk::TreeView::Column("网络发送"));
    col_network_send->pack_start(m_columns.m_col_network_send);
    m_tree_view.append_column(*col_network_send);
    col_network_send->set_sort_column(m_columns.m_col_network_send);
    
    // 设置选择模式
    m_tree_view.get_selection()->set_mode(Gtk::SELECTION_SINGLE);
    
    // 连接选择变化信号
    m_tree_view.signal_cursor_changed().connect(
        sigc::mem_fun(*this, &ProcessTable::on_selection_changed));
    
    // 启用右键菜单
    m_tree_view.add_events(Gdk::BUTTON_PRESS_MASK);
    m_tree_view.signal_button_press_event().connect(
        sigc::mem_fun(*this, &ProcessTable::on_button_press_event), false);
    
    // 添加TreeView到ScrolledWindow
    add(m_tree_view);
    show_all_children();
    
    // 连接排序信号，确保用户点击列标题时按我们的规则排序
    for (int i = 0; i < 13; i++) {
        Gtk::TreeViewColumn* column = m_tree_view.get_column(i);
        if (column) {
            // 使用lambda捕获this和column的副本，避免悬空引用
            Gtk::TreeViewColumn* captured_column = column;
            int column_index = i;
            column->signal_clicked().connect([this, captured_column, column_index]() {
                // 获取当前排序状态
                int sort_column_id;
                Gtk::SortType sort_order;
                bool has_sort = m_ref_tree_model->get_sort_column_id(sort_column_id, sort_order);
                
                // 判断是否是第一次点击该列（即之前未排序或排序的是其他列）
                if (!has_sort || sort_column_id != column_index) {
                    // 第一次点击该列，使用升序（从小到大）
                    m_ref_tree_model->set_sort_column(column_index, Gtk::SORT_ASCENDING);
                    
                    // 更新UI指示器
                    captured_column->set_sort_order(Gtk::SORT_ASCENDING);
                    captured_column->set_sort_indicator(true);
                    
                    // 取消其他列的排序指示器
                    for (int j = 0; j < 13; j++) {
                        if (j != column_index) {
                            Gtk::TreeViewColumn* other_col = m_tree_view.get_column(j);
                            if (other_col) {
                                other_col->set_sort_indicator(false);
                            }
                        }
                    }
                } else {
                    // 不是第一次点击该列，在升序和降序之间切换
                    Gtk::SortType new_order = (sort_order == Gtk::SORT_ASCENDING) ? 
                                              Gtk::SORT_DESCENDING : Gtk::SORT_ASCENDING;
                    m_ref_tree_model->set_sort_column(column_index, new_order);
                    
                    // 更新UI指示器
                    captured_column->set_sort_order(new_order);
                    captured_column->set_sort_indicator(true);
                }
            });
        }
    }
    
    // 设置默认按CPU使用率升序排序（符合第一次点击的规则）
    m_ref_tree_model->set_sort_column(4, Gtk::SORT_ASCENDING);
    
    // 为CPU列设置初始排序指示器
    m_tree_view.get_column(4)->set_sort_order(Gtk::SORT_ASCENDING);
    m_tree_view.get_column(4)->set_sort_indicator(true);
}

ProcessTable::~ProcessTable() {
    // 空析构函数
}

void ProcessTable::update_data(const std::vector<ProcessInfo>& processes) {
    // 保存当前选中的PID
    int previously_selected_pid = m_selected_pid;
    
    // 清空现有数据
    m_ref_tree_model->clear();
    
    // 填充新数据
    Gtk::TreeIter selected_iter;
    bool found_selected = false;
    
    for (const auto& process : processes) {
        Gtk::TreeModel::Row row = *(m_ref_tree_model->append());
        
        row[m_columns.m_col_name] = process.name;
        row[m_columns.m_col_pid] = process.pid;
        row[m_columns.m_col_status] = process.status;
        row[m_columns.m_col_user] = process.user;
        
        // 格式化CPU百分比
        std::stringstream cpu_ss;
        cpu_ss << std::fixed << std::setprecision(1) << process.cpu_percent;
        row[m_columns.m_col_cpu] = cpu_ss.str() + "%";
        
        // 格式化内存使用量
        std::stringstream memory_ss;
        if (process.memory_mb < 1) {
            memory_ss << std::fixed << std::setprecision(1) << process.memory_mb * 1024 << " KB";
        } else if (process.memory_mb < 1024) {
            memory_ss << std::fixed << std::setprecision(1) << process.memory_mb << " MB";
        } else {
            memory_ss << std::fixed << std::setprecision(1) << process.memory_mb / 1024 << " GB";
        }
        row[m_columns.m_col_memory] = memory_ss.str();
        
        // 格式化运行时间
        row[m_columns.m_col_time] = process.running_time;
        
        row[m_columns.m_col_command] = process.command_line;
        row[m_columns.m_col_priority] = process.priority;
        
        // 格式化磁盘读取速度
        std::stringstream disk_read_ss;
        if (process.disk_read_kb < 1024) {
            disk_read_ss << std::fixed << std::setprecision(1) << process.disk_read_kb << " KB/s";
        } else {
            disk_read_ss << std::fixed << std::setprecision(1) << process.disk_read_kb / 1024 << " MB/s";
        }
        row[m_columns.m_col_disk_read] = disk_read_ss.str();
        
        // 格式化磁盘写入速度
        std::stringstream disk_write_ss;
        if (process.disk_write_kb < 1024) {
            disk_write_ss << std::fixed << std::setprecision(1) << process.disk_write_kb << " KB/s";
        } else {
            disk_write_ss << std::fixed << std::setprecision(1) << process.disk_write_kb / 1024 << " MB/s";
        }
        row[m_columns.m_col_disk_write] = disk_write_ss.str();
        
        // 格式化网络接收速度
        std::stringstream network_recv_ss;
        if (process.network_recv_kb < 1024) {
            network_recv_ss << std::fixed << std::setprecision(1) << process.network_recv_kb << " KB/s";
        } else {
            network_recv_ss << std::fixed << std::setprecision(1) << process.network_recv_kb / 1024 << " MB/s";
        }
        row[m_columns.m_col_network_recv] = network_recv_ss.str();
        
        // 格式化网络发送速度
        std::stringstream network_send_ss;
        if (process.network_send_kb < 1024) {
            network_send_ss << std::fixed << std::setprecision(1) << process.network_send_kb << " KB/s";
        } else {
            network_send_ss << std::fixed << std::setprecision(1) << process.network_send_kb / 1024 << " MB/s";
        }
        row[m_columns.m_col_network_send] = network_send_ss.str();
        
        // 如果这是之前选中的进程，保存其迭代器
        if (process.pid == previously_selected_pid) {
            selected_iter = row;
            found_selected = true;
        }
    }
    
    // 如果找到了之前选中的进程，则选中它并滚动到该位置
    if (found_selected) {
        m_tree_view.get_selection()->select(selected_iter);
        m_tree_view.scroll_to_row(m_ref_tree_model->get_path(selected_iter));
    }
}

int ProcessTable::get_selected_pid() const {
    return m_selected_pid;
}

Glib::RefPtr<Gtk::TreeSelection> ProcessTable::get_selection() {
    return m_tree_view.get_selection();
}

void ProcessTable::set_selected_pid(int pid) {
    // 遍历所有行，找到匹配的PID并选中该行
    for (auto iter = m_ref_tree_model->children().begin(); 
         iter != m_ref_tree_model->children().end(); ++iter) {
        Gtk::TreeModel::Row row = *iter;
        if (row[m_columns.m_col_pid] == pid) {
            m_tree_view.get_selection()->select(iter);
            m_selected_pid = pid;
            m_selected_process_name = row[m_columns.m_col_name];
            return;
        }
    }
    
    // 如果没有找到匹配的PID，清除选择
    m_tree_view.get_selection()->unselect_all();
    m_selected_pid = -1;
    m_selected_process_name.clear();
}

void ProcessTable::on_selection_changed() {
    // 获取选中的行
    Glib::RefPtr<Gtk::TreeSelection> selection = m_tree_view.get_selection();
    Gtk::TreeModel::iterator iter = selection->get_selected();
    
    if (iter) {
        Gtk::TreeModel::Row row = *iter;
        m_selected_pid = row[m_columns.m_col_pid];
        m_selected_process_name = row[m_columns.m_col_name];
    } else {
        m_selected_pid = -1;
        m_selected_process_name.clear();
    }
}

bool ProcessTable::on_button_press_event(GdkEventButton* event) {
    // 处理右键点击事件
    if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
        // 先更新选择
        on_selection_changed();
        
        // 只有在有选中进程时才显示菜单
        if (m_selected_pid > 0) {
            // 创建右键菜单（使用Gtk::manage管理，确保生命周期）
            Gtk::Menu* popup_menu = Gtk::manage(new Gtk::Menu());
            
            Gtk::MenuItem* menu_end_task = new Gtk::MenuItem("结束任务");
            menu_end_task->signal_activate().connect(
                sigc::mem_fun(*this, &ProcessTable::on_end_task));
            popup_menu->append(*menu_end_task);
            
            Gtk::MenuItem* menu_end_process_tree = new Gtk::MenuItem("结束进程树");
            menu_end_process_tree->signal_activate().connect(
                sigc::mem_fun(*this, &ProcessTable::on_end_process_tree));
            popup_menu->append(*menu_end_process_tree);
            
            Gtk::SeparatorMenuItem* separator1 = new Gtk::SeparatorMenuItem();
            popup_menu->append(*separator1);
            
            Gtk::MenuItem* menu_copy_command = new Gtk::MenuItem("复制命令行");
            menu_copy_command->signal_activate().connect(
                sigc::mem_fun(*this, &ProcessTable::on_copy_command_line));
            popup_menu->append(*menu_copy_command);
            
            Gtk::SeparatorMenuItem* separator2 = new Gtk::SeparatorMenuItem();
            popup_menu->append(*separator2);
            
            Gtk::MenuItem* menu_open_directory = new Gtk::MenuItem("打开进程所在目录");
            menu_open_directory->signal_activate().connect(
                sigc::mem_fun(*this, &ProcessTable::on_open_directory));
            popup_menu->append(*menu_open_directory);
            
            Gtk::MenuItem* menu_properties = new Gtk::MenuItem("属性");
            menu_properties->signal_activate().connect(
                sigc::mem_fun(*this, &ProcessTable::on_show_properties));
            popup_menu->append(*menu_properties);
            
            popup_menu->show_all();
            
            // 显示右键菜单
            popup_menu->popup_at_pointer(reinterpret_cast<GdkEvent*>(event));
        }
        
        return true; // 事件已处理
    }
    
    return Gtk::ScrolledWindow::on_button_press_event(event);
}

void ProcessTable::on_end_task() {
    if (m_selected_pid <= 0) return;
    
    // 创建确认对话框
    std::stringstream msg;
    msg << "确定要结束进程 " << m_selected_process_name << " (PID: " << m_selected_pid << ") 吗？";
    
    Gtk::MessageDialog dialog(msg.str(), false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
    dialog.set_title("确认");
    
    int result = dialog.run();
    if (result == Gtk::RESPONSE_YES) {
        // 尝试终止进程
        if (kill(m_selected_pid, SIGTERM) == 0) {
            Gtk::MessageDialog success_dialog("已发送终止信号给进程", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
            success_dialog.run();
        } else {
            Gtk::MessageDialog error_dialog("无法终止进程", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            error_dialog.run();
        }
    }
}

void ProcessTable::on_end_process_tree() {
    if (m_selected_pid <= 0) return;
    
    // 创建确认对话框
    std::stringstream msg;
    msg << "确定要结束进程树 " << m_selected_process_name << " (PID: " << m_selected_pid << ") 吗？这将结束该进程及其所有子进程。";
    
    Gtk::MessageDialog dialog(msg.str(), false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
    dialog.set_title("确认");
    
    int result = dialog.run();
    if (result == Gtk::RESPONSE_YES) {
        // 尝试终止进程树
        if (kill(m_selected_pid, SIGTERM) == 0) {
            Gtk::MessageDialog success_dialog("已发送终止信号给进程树", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
            success_dialog.run();
        } else {
            Gtk::MessageDialog error_dialog("无法终止进程树", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            error_dialog.run();
        }
    }
}

void ProcessTable::on_open_directory() {
    if (m_selected_pid <= 0) return;
    
    // 构造进程可执行文件路径
    std::stringstream exe_path_ss;
    exe_path_ss << "/proc/" << m_selected_pid << "/exe";
    
    char real_path[1024];
    ssize_t len = readlink(exe_path_ss.str().c_str(), real_path, sizeof(real_path) - 1);
    if (len != -1) {
        real_path[len] = '\0';
        
        // 获取目录路径
        std::string exe_path(real_path);
        size_t pos = exe_path.find_last_of('/');
        if (pos != std::string::npos) {
            std::string directory = exe_path.substr(0, pos);
            
            // 尝试使用xdg-open打开目录
            try {
                std::vector<std::string> argv = {"xdg-open", directory};
                Glib::spawn_async("", argv, Glib::SpawnFlags::SPAWN_SEARCH_PATH);
            } catch (const Glib::Error& ex) {
                Gtk::MessageDialog error_dialog("无法打开目录", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
                error_dialog.run();
            }
        }
    } else {
        Gtk::MessageDialog error_dialog("无法获取进程可执行文件路径", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        error_dialog.run();
    }
}

void ProcessTable::on_show_properties() {
    if (m_selected_pid <= 0) return;
    
    // 创建属性对话框
    std::stringstream title;
    title << "进程属性 - " << m_selected_process_name;
    
    Gtk::Dialog properties_dialog(title.str());
    properties_dialog.set_default_size(500, 400);
    
    // 创建文本视图显示进程信息
    Gtk::TextView text_view;
    text_view.set_editable(false);
    
    // 构造进程信息
    std::stringstream info_ss;
    info_ss << "进程名称: " << m_selected_process_name << "\n";
    info_ss << "进程ID: " << m_selected_pid << "\n";
    
    // 读取更多进程信息
    std::stringstream status_path_ss;
    status_path_ss << "/proc/" << m_selected_pid << "/status";
    
    std::ifstream status_file(status_path_ss.str());
    if (status_file.is_open()) {
        std::string line;
        while (std::getline(status_file, line)) {
            info_ss << line << "\n";
        }
        status_file.close();
    }
    
    // 读取命令行
    std::stringstream cmdline_path_ss;
    cmdline_path_ss << "/proc/" << m_selected_pid << "/cmdline";
    
    std::ifstream cmdline_file(cmdline_path_ss.str());
    if (cmdline_file.is_open()) {
        info_ss << "命令行: ";
        std::string cmdline;
        std::getline(cmdline_file, cmdline, '\0');
        info_ss << cmdline << "\n";
        cmdline_file.close();
    }
    
    text_view.get_buffer()->set_text(info_ss.str());
    
    // 添加滚动窗口
    Gtk::ScrolledWindow scrolled_window;
    scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    scrolled_window.add(text_view);
    
    properties_dialog.get_content_area()->pack_start(scrolled_window);
    properties_dialog.add_button("关闭", Gtk::RESPONSE_OK);
    properties_dialog.show_all_children();
    
    properties_dialog.run();
}

void ProcessTable::on_copy_command_line() {
    if (m_selected_pid <= 0) return;
    
    // 获取选中行的命令行
    Glib::RefPtr<Gtk::TreeSelection> selection = m_tree_view.get_selection();
    Gtk::TreeModel::iterator iter = selection->get_selected();
    
    if (iter) {
        Gtk::TreeModel::Row row = *iter;
        std::string command_line = row[m_columns.m_col_command];
        
        // 复制到剪贴板
        Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get();
        clipboard->set_text(command_line);
        
        // 显示确认消息
        Gtk::MessageDialog dialog(*dynamic_cast<Gtk::Window*>(get_toplevel()), 
                                 "命令行已复制到剪贴板", 
                                 false, 
                                 Gtk::MESSAGE_INFO, 
                                 Gtk::BUTTONS_OK);
        dialog.run();
    }
}
